#define TYPE_HS2101 "hs2101"
#define HS2101(obj) OBJECT_CHECK(hs2101_state, (obj), TYPE_HS2101)
#define HS2101_MMIO_SIZE 0x1000
#define LBC_CS_NUM 4

#ifdef DEBUG_HS2101
#define DPRINTF(_x ...) printf(_x)
#else
#define DPRINTF(_x ...)
#endif

// localbus 寄存器
#define LB_CS0_BASE_ADDR        0X0000      //片选0基地址寄存器
#define LB_CS1_BASE_ADDR        0x0004      //片选1基地址寄存器
#define LB_CS2_BASE_ADDR        0x0008      //片选2基地址寄存器
#define LB_CS3_BASE_ADDR        0x000C      //片选3基地址寄存器
#define LB_CS0_CTRL             0x0020      //片选0控制寄存器
#define LB_CS1_CTRL             0x0024      //片选1控制寄存器
#define LB_CS2_CTRL             0x0028      //片选2控制寄存器
#define LB_CS3_CTRL             0x002C      //片选3控制寄存器
#define LB_CS0_T_SET0           0x0040      //片选0的时序参数配置寄存器0
#define LB_CS0_T_SET1           0x0044      //片选0的时序参数配置寄存器1
#define LB_CS0_T_SET2           0x0048      //片选0的时序参数配置寄存器2
#define LB_CS1_T_SET0           0x004C      //片选1的时序参数配置寄存器0
#define LB_CS1_T_SET1           0x0050      //片选1的时序参数配置寄存器1
#define LB_CS1_T_SET2           0x0054      //片选1的时序参数配置寄存器2
#define LB_CS2_T_SET0           0x0058      //片选2的时序参数配置寄存器0
#define LB_CS2_T_SET1           0x005C      //片选2的时序参数配置寄存器1
#define LB_CS2_T_SET2           0x0060      //片选2的时序参数配置寄存器2
#define LB_CS3_T_SET0           0x0064      //片选3的时序参数配置寄存器0
#define LB_CS3_T_SET1           0x0068      //片选3的时序参数配置寄存器1
#define LB_CS3_T_SET2           0x006C      //片选3的时序参数配置寄存器2
#define LB_INTMSK               0x00A0      //中断屏蔽寄存器
#define LB_INTSTS               0x00A4      //中断状态寄存器
#define LB_RINT                 0x00A8      //原始中断状态寄存器
#define LB_RDY_TOUT_0           0x00AC      //片选0超时时间
#define LB_RDY_TOUT_1           0x00B0      //片选1超时时间
#define LB_RDY_TOUT_2           0x00B4      //片选2超时时间
#define LB_RDY_TOUT_3           0x00B8      //片选3超时时间
#define LB_CTRL                 0x00CC      //总体控制寄存器
#define LB_PROT_ADDR_START_0    0x00D0      //PORT_ADDR_STRAT_0寄存器
#define LB_PROT_ADDR_OVER_0     0x00D4      //PORT_ADDR_OVER_0寄存器
#define LB_PROT_ADDR_START_1    0x00D8      //PORT_ADDR_STRAT_1寄存器
#define LB_PROT_ADDR_OVER_1     0x00DC      //PORT_ADDR_OVER_1寄存器
#define LB_PROT_ADDR_START_2    0x00E0      //PORT_ADDR_STRAT_2寄存器
#define LB_PROT_ADDR_OVER_2     0x00E4      //PORT_ADDR_OVER_2寄存器
#define LB_PROT_ADDR_START_3    0x00E8      //PORT_ADDR_STRAT_2寄存器
#define LB_PROT_ADDR_OVER_3     0x00EC      //PORT_ADDR_OVER_3寄存器
#define LB_PROT_ADDR_START_4    0x00F0      //PORT_ADDR_STRAT_3寄存器
#define LB_PROT_ADDR_OVER_4     0x00F4      //PORT_ADDR_OVER_4寄存器
#define LB_PROT_ADDR_START_5    0x00F8      //PORT_ADDR_STRAT_4寄存器
#define LB_PROT_ADDR_OVER_5     0x00FC      //PORT_ADDR_OVER_5寄存器
#define LB_PROT_ADDR_START_6    0x0100      //PORT_ADDR_STRAT_6寄存器
#define LB_PROT_ADDR_OVER_6     0x0104      //PORT_ADDR_OVER_6寄存器
#define LB_PROT_ADDR_START_7    0x0108      //PORT_ADDR_STRAT_7寄存器
#define LB_PROT_ADDR_OVER_7     0x010C      //PORT_ADDR_OVER_7寄存器
#define LB_NOR_CMD0_ADDR        0x0110      //nor flash命令字0地址配置
#define LB_NOR_CMD0_MASK        0x0114      //nor flash命令字0地址mask配置
#define LB_NOR_CMD1_ADDR        0x0118      //nor flash命令字1地址配置
#define LB_NOR_CMD1_MASK        0x011C      //nor flash命令字1地址mask配置
#define LB_NOR_CMD2_ADDR        0x0120      //nor flash命令字2地址配置
#define LB_NOR_CMD2_MASK        0x0124      //nor flash命令字2地址mask配置
#define LB_NOR_CMD3_ADDR        0x0128      //nor flash命令字3地址配置
#define LB_NOR_CMD3_MASK        0x012C      //nor flash命令字3地址mask配置
#define LB_HL_PROT_KEY0         0x0130      //高级写保护配置字
#define LB_HL_PROT_KEY1         0x0134      //高级写保护配置字
#define LB_HL_PROT_KEY2         0x0138      //高级写保护配置字
#define LB_HL_PROT_KEY3         0x013C      //高级写保护配置字
#define DBG_ST0                 0x0140      //debug状态寄存器0
#define DBG_OVER_TIME_ADDR      0x0144      //debug状态寄存器1
#define DBG_T_CFG               0x0148      //debug状态寄存器2
#define CF_CARD_ST              0x0150      //CF状态寄存器
#define LB_CFG_T_UPDATE_EN      0x0154      //时序配置更新使能
#define WP_RSP_ERR_EN           0x0158      //写保护返回error使能寄存器

typedef struct {
    uint32_t cs0_base_addr;
    uint32_t cs1_base_addr;
    uint32_t cs2_base_addr;
    uint32_t cs3_base_addr;
    uint32_t cs0_ctrl;
    uint32_t cs1_ctrl;
    uint32_t cs2_ctrl;
    uint32_t cs3_ctrl;
    uint32_t cs0_t_set0;
    uint32_t cs0_t_set1;
    uint32_t cs0_t_set2;
    uint32_t cs1_t_set0;
    uint32_t cs1_t_set1;
    uint32_t cs1_t_set2;
    uint32_t cs2_t_set0;
    uint32_t cs2_t_set1;
    uint32_t cs2_t_set2;
    uint32_t cs3_t_set0;
    uint32_t cs3_t_set1;
    uint32_t cs3_t_set2;
    uint32_t initmsk;
    uint32_t initsts;
    uint32_t rint;
    uint32_t rdy_tout_0;
    uint32_t rdy_tout_1;
    uint32_t rdy_tout_2;
    uint32_t rdy_tout_3;
    uint32_t total_ctrl;
    uint32_t prot_addr_start_0;
    uint32_t prot_addr_over_0;
    uint32_t prot_addr_start_1;
    uint32_t prot_addr_over_1;
    uint32_t prot_addr_start_2;
    uint32_t prot_addr_over_2;
    uint32_t prot_addr_start_3;
    uint32_t prot_addr_over_3;
    uint32_t prot_addr_start_4;
    uint32_t prot_addr_over_4;
    uint32_t prot_addr_start_5;
    uint32_t prot_addr_over_5;
    uint32_t prot_addr_start_6;
    uint32_t prot_addr_over_6;
    uint32_t prot_addr_start_7;
    uint32_t prot_addr_over_7;
    uint32_t nor_cmd0_addr;
    uint32_t nor_cmd0_mask;
    uint32_t nor_cmd1_addr;
    uint32_t nor_cmd1_mask;
    uint32_t nor_cmd2_addr;
    uint32_t nor_cmd2_mask;
    uint32_t nor_cmd3_addr;
    uint32_t nor_cmd3_mask;
    uint32_t hl_port_key0;
    uint32_t hl_port_key1;
    uint32_t hl_port_key2;
    uint32_t hl_port_key3;
    uint32_t dbg_st0;
    uint32_t dbg_over_time_addr;
    uint32_t dbg_t_cfg;
    uint32_t cf_card_st;
    uint32_t cfg_t_update_en;
    uint32_t wp_rsp_err_en;
} hs2101_regs;

typedef struct {
    SysBusDevice parent_obj;
    qemu_irq irq;
    MemoryRegion iomem;
    LBCBus *bus;
    hs2101_regs regs;

    struct lbc_iomem_cs_file_s {
        uint64_t base_addr;
        uint64_t addr_size;
        MemoryRegion container;
        MemoryRegion cs_iomem;
        DeviceState *dev;
        LBCBus *bus;
        bool is_cs_mapping;
    } cs_file[LBC_CS_NUM];
} hs2101_state;